﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once


#include "GbmpConstants.h"
#include "Vector3d.h"

#include <cstring>

namespace gcmp
{

    /// \brief 3x3矩阵的基本定义
    ///
    /// 
    class GCMP_MATH_INTERFACE_EXPORT Matrix3d
    {
    public:
        DEFINE_VISUAL_TYPE_DOUBLE()

    public:
        /// \brief   创建单位矩阵
        ///
        /// \return  单位矩阵
        static Matrix3d CreateIdentity();

        /// \brief  使当前矩阵变为它的逆
        ///
        /// \return true:成功， false: 失败
        bool MakeInverse();

        /// \brief  使当前矩阵变为单位矩阵
        ///
        /// \return  true:成功， false: 失败
        bool MakeIdentity();

        /// \brief   判断矩阵是否为单位阵
        ///
        /// \return  true: 是单位阵， false: 不是单位阵
        bool IsIdentity() const;

    public:

        /// \brief  缺省构造函数，缺省为单位矩阵
        ///
        /// \return 
        Matrix3d();

        /// \brief   构造函数，根据9个数值，构造矩阵
        ///
        /// \param a11  第一行第一值
        /// \param a12  第一行第二值
        /// \param a13  第一行第三值
        /// \param a21  第二行第一值
        /// \param a22  第二行第二值
        /// \param a23  第二行第三值
        /// \param a31  第三行第一值
        /// \param a32  第三行第二值
        /// \param a33  第三行第三值
        /// 
        Matrix3d(double a11, double a12, double a13,
            double a21, double a22, double a23,
            double a31, double a32, double a33);

        /// \brief  构造函数  用三个行向量，构造矩阵
        ///
        /// \param v1  第一个向量
        /// \param v2  第二个向量
        /// \param v3  第三个向量
        /// \return 
        Matrix3d(const Vector3d &  v1, const Vector3d &  v2, const Vector3d &  v3);

        /// \brief   矩阵的拷贝构造函数
        ///
        /// \param matrix  传入的矩阵
        ///  
        Matrix3d(const Matrix3d & matrix);

        /// \brief  设置矩阵的值
        ///
        /// \param a11  第一行第一值
        /// \param a12  第一行第二值
        /// \param a13  第一行第三值
        /// \param a21  第二行第一值
        /// \param a22  第二行第二值
        /// \param a23  第二行第三值
        /// \param a31  第三行第一值
        /// \param a32  第三行第二值
        /// \param a33  第三行第三值
        /// \return  true:成功，false:失败
        bool Set(double a11, double a12, double a13,
                 double a21, double a22, double a23,
                 double a31, double a32, double a33);

        /// \brief  使矩阵的每个值为0
        ///  
        void MakeZero();

        /// \brief   用代数余子式计算3阶矩阵的行列式
        ///
        /// \return  行列式的值
        double Determinant() const;
 
        /// \brief   返回矩阵中的旋转部分对应的坐标轴分量
        /// \param xAxis  x轴
        /// \param yAxis  y轴
        ///
        void GetRotationAxes(Vector2d& xAxis, Vector2d& yAxis) const;

        /// \brief  获取当前矩阵的逆矩阵
        ///
        /// \param inversedMat  当前矩阵的逆矩阵
        /// \return  true:成功，false:失败
        bool GetInverse(Matrix3d& inversedMat)const;

        /// \brief   自身矩阵不变，获得其转置矩阵
        ///
        /// \return 转置矩阵
        Matrix3d GetTranspose() const;

        /// \brief   设置自身矩阵为转置矩阵
        /// 
        void MakeTranspose();

        /// \brief   设置矩阵位移分量
        ///
        /// \param t  位移分量
        /// \return 
        bool SetTranslation(const Vector2d & t);

        /// \brief   获取矩阵位移分量
        ///
        /// \return  位移分量
        const Vector2d GetTranslation() const;

        /// \brief   设置矩阵位移分量,旋转和缩放分量不变
        ///
        /// \param tx  平移X分量
        /// \param ty  平移Y分量
        /// \return 
        bool SetTranslation(double tx, double ty);

        /// \brief   设置自身矩阵为平移矩阵,矩阵重置为单位矩阵后设置位移分量
        ///
        /// \param t  平移量
        /// \return 
        void MakeTranslate(const Vector2d & t);

        /// \brief   根据平移向量的二个分量设置自身矩阵为平移矩阵,矩阵重置为单位矩阵后设置位移分量
        ///
        /// \param tx  平移X分量
        /// \param ty  平移Y分量
        ///
        void MakeTranslate(double tx, double ty);

        /// \brief   设置自身矩阵为绕任意点的旋转矩阵,矩阵重置为单位矩阵后设置旋转分量
        ///
        /// \param Pos  中心点
        /// \param Angle  旋转角度的弧度值，正值表示逆时针方向
        ///
        void MakeRotate(const Vector2d& Pos, double Angle);

        /// \brief  设置自身矩阵等比缩放矩阵,矩阵重置为单位矩阵后设置缩放分量
        ///
        /// \param Scale  缩放比例
        /// \return 
        void MakeScale(double Scale);

        /// \brief   设置自身矩阵非等比缩放矩阵,矩阵重置为单位矩阵后设置缩放分量
        ///
        /// \param Scale  缩放比例
        /// \return 
        void MakeScale(const Vector2d& Scale);

        /// \brief   设置自身矩阵为任意轴的镜像矩阵
        ///
        /// \param Pos  镜像轴的基点
        /// \param Dir  镜像轴的方向
        ///
        void MakeMirror(const Vector2d& Pos, const Vector2d& Dir);

        /// \brief   返回二维数组中某行的指针
        ///
        /// \param i  给定行
        /// \return 某行的指针
        double * operator [](int i);

        /// \brief   返回二维数组中某行的指针
        ///
        /// \param i  给定行
        /// \return 某行的指针
        const double * operator [](int i) const;

        /// \brief   矩阵赋值操作
        ///
        /// \param m  传入矩阵
        /// \return 自身矩阵的引用
        Matrix3d & operator =(const Matrix3d & m);

        /// \brief   自身矩阵乘以传入矩阵，结果设置为自身
        ///
        /// \param m  传入矩阵
        /// \return 自身矩阵的引用
        Matrix3d & operator *=(const Matrix3d & matrix);

        /// \brief   三维点src左乘矩阵，注意若是二维点转三维点应该用齐次坐标
        ///
        /// \param src  传入的三维点
        /// \return  返回的三维点
        Vector3d MultiLeft(const Vector3d &  src) const;

        /// \brief  三维点src右乘矩阵，注意若是二维点转三维点应该用齐次坐标
        ///
        /// \param v  传入的三维点
        /// \return  返回的三维点
        Vector3d MultRight(const Vector3d & v);

        /// \brief   传入矩阵右乘当前矩阵，结果设置为自身矩阵
        ///
        /// \param m  传入矩阵
        /// \return   当前矩阵的引用
        Matrix3d & MultRight(const Matrix3d & m);

        /// \brief 把坐标系对象按照规定格式字符串输出
        ///
        /// \return 字符串
        std::wstring GetStringForDebug() const;

        /// \brief   根据字符串生成矩阵
        ///
        /// \param wstr  传入的字符串
        /// \return   生成的矩阵
        static Matrix3d LoadFromString(const std::wstring& wstr);

    private:
        double m_data[3][3];
    };

    /// \brief   两矩阵相乘，返回结果矩阵
    ///
    /// \param m1  传入矩阵1
    /// \param m2  传入矩阵2
    /// \return 结果矩阵
    GCMP_MATH_INTERFACE_EXPORT Matrix3d operator *(const Matrix3d & m1, const Matrix3d & m2);

    /// \brief   矩阵乘以列向量，返回列向量
    ///
    /// \param m  传入矩阵
    /// \param v  列向量
    /// \return 结果向量
    GCMP_MATH_INTERFACE_EXPORT Vector3d operator *(const Matrix3d & m, const Vector3d & v);

    /// \brief   行向量乘以矩阵，返回行向量
    ///
    /// \param v  行向量
    /// \param m  矩阵
    /// \return 结果向量
    GCMP_MATH_INTERFACE_EXPORT Vector3d operator *(const Vector3d &  v, const Matrix3d & m);

    /// \brief 判断两矩阵是否相等
    ///
    /// \param m1   矩阵1
    /// \param m2   矩阵2
    /// \return true: 相等，false: 不相等
    GCMP_MATH_INTERFACE_EXPORT bool operator ==(const Matrix3d & m1, const Matrix3d & m2);

    /// \brief 判断两矩阵是否不相等
    ///
    /// \param m1   矩阵1
    /// \param m2   矩阵2
    /// \return true: 不相等，false: 相等
    GCMP_MATH_INTERFACE_EXPORT bool operator !=(const Matrix3d & m1, const Matrix3d & m2);

} // namespace

